/**
 * Copyright 2011-2011 - Members of the Chaupal Community
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package net.chaupal.Impl.BoostedObject;

import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Provides a serializable version of {@link BoostedObject}.
 */
public class BoostedSerializableObject extends BoostedObject
        implements Serializable, Boosted { 

    /**
     * Log
     */
    private static final Logger LOG
            = LoggerFactory.getLogger(BoostedSerializableObject.class);

    /**
     * Default constructor.
     */
    public BoostedSerializableObject() {
        
        // Invoking another constructor
        this("");
        
    }

    /**
     * Constructor taking a name for this object.
     * 
     * @param name 
     */
    public BoostedSerializableObject(String name) {

        // Calling super
        super(name);
        
    }
    
    /**
     * Copy constructor.
     * 
     * @param toCopy the object to copy
     */ 
    public BoostedSerializableObject(BoostedSerializableObject toCopy) {
        
        super(toCopy);
        
    }
    
    /**
     * Serialization constructor.
     * 
     * @param unserialize 
     */
    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    protected BoostedSerializableObject(SerializationProxy unserialize) {
        
        // We initialize our object properly
        this(unserialize.name);
        
    }

    /**
     * Instead of serializing this class, we provide a proxy instead. This 
     * method is automatically called in the serialization process.
     * 
     * @return a serialization proxy for this class
     */
    private Object writeReplace() {
        return new SerializationProxy(this);
    }

    /**
     * This method can be hijacked to insert uncontrolled or unwanted 
     * serialized object. We neutralize it.
     * 
     * @param stream an object input stream
     * @throws InvalidObjectException always
     */
    public final void readObject(ObjectInputStream stream)
            throws InvalidObjectException {
        
        String tmp = "Serialization proxy required";
        InvalidObjectException ex = new InvalidObjectException(tmp);
        LOG.warn(tmp, ex);
        throw ex;
        
    }

    /**
     * Replacement for this object for serialization. It should not be made
     * final or private, since classes inheriting this object will extend this
     * proxy with their own proxy.
     */
    protected static class SerializationProxy implements Serializable {

        // For serilaization
        private static final long serialVersionUID = 1L;

        // Serialized attributes
        private final String name;
        
        @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
        SerializationProxy(BoostedSerializableObject inThis) {
            
            // Initialization
            this.name = inThis.getName();
            
        }

        /**
         * This method is called when the proxy is unserialized.
         * 
         * @return an unserialized 
         */
        private Object readResolve() {
            
            // We use the protected constructor for serialization
            return new BoostedSerializableObject(this);
            
        }

    }
    
}
